home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / lzhtv10.arc / LZHTV.PAS < prev    next >
Pascal/Delphi Source File  |  1989-04-21  |  13KB  |  583 lines

  1.  
  2. (*
  3.  * Copyright 1987, 1989 Samuel H. Smith;  All rights reserved
  4.  *
  5.  * Do not distribute modified versions without my permission.
  6.  * Do not remove or alter this notice or any other copyright notice.
  7.  * If you use this in your own program you must distribute source code.
  8.  * Do not use any of this in a commercial product.
  9.  *
  10.  *)
  11.  
  12. (*
  13.  * LzhTV - text view utility/door for LHARC-format .LZH files
  14.  *
  15.  *)
  16.  
  17. {$I prodef.inc}
  18. {$M 5000,0,0}  {minstack,minheap,maxheap}
  19. {$D+}          {Global debug information}
  20. {$L+}          {Local debug information}
  21.  
  22. program LzhTV;
  23.  
  24. Uses
  25.    Dos, DosMem, MiniCrt, Mdosio, Tools, CInput;
  26.  
  27. const
  28.    version = 'LzhTV:  LZH Text Viewer v1.0 of 04-21-89;  (C) 1989 S.H.Smith';
  29.  
  30.  
  31. (* ----------------------------------------------------------- *)
  32. (*
  33.  * file layout declarations
  34.  *
  35.  *)
  36.  
  37. type
  38.    lharc_header_rec = record
  39.       header_length:       byte;                {0=end of file}
  40.       header_check:        byte;                {checksum of remaining bytes}
  41.       compression_type:    array[1..5] of char; {'-lh0-'=store '-lh1-'=LZHuf}
  42.       compressed_size:     longint;
  43.       original_size:       longint;
  44.       file_time:           word;
  45.       file_date:           word;
  46.       file_attributes:     word;
  47.       file_name_length:    byte;
  48.       file_name:           string[65];
  49.       crc16:               word;
  50.    end;
  51.  
  52.  
  53. (* ----------------------------------------------------------- *)
  54. (*
  55.  * input file variables
  56.  *
  57.  *)
  58.  
  59. const
  60.    uinbufsize = 512;    {input buffer size}
  61. var
  62.    fileeof:       boolean;
  63.    infd:          dos_handle;
  64.    infn:          dos_filename;
  65.    inbuf:         array[1..uinbufsize] of byte;
  66.    inpos:         integer;
  67.    incnt:         integer;
  68.  
  69.    header:        lharc_header_rec;
  70.  
  71.  
  72. (* ----------------------------------------------------------- *)
  73. (*
  74.  * output stream variables
  75.  *
  76.  *)
  77.  
  78. const
  79.    obufsize = 4096;     (* output buffer size; should be 4096 *)
  80.    lookahead = 60;      (* lookahead buffer size *)
  81.    THRESHOLD = 2;
  82.    max_binary =   50;   {non-printing count before binary file trigger}
  83.    max_linelen =  200;  {line length before binary file triggered}
  84.  
  85. var
  86.    outbuf:        array[0..obufsize] of byte; {for rle look-back}
  87.    outpos:        longint;                 {absolute position in outfile}
  88.  
  89.    lson:    array[0..obufsize+1] of integer;
  90.    rson:    array[0..obufsize+257] of integer;
  91.    dad:     array[0..obufsize+1] of integer;
  92.  
  93.    uoutbuf:       string[max_linelen];    {disp line buffer}
  94.    binary_count:  integer;                {non-text chars so far}
  95.  
  96.  
  97. (* ----------------------------------------------------------- *)
  98. (*
  99.  * other working storage
  100.  *
  101.  *)
  102.  
  103. var
  104.    expand_files:        boolean;
  105.    header_present:      boolean;
  106.    default_pattern:     string20;
  107.    pattern:             string20;
  108.    action:              string20;
  109.  
  110.  
  111.  
  112. (* ----------------------------------------------------
  113.  *
  114.  *    file input/output handlers
  115.  *
  116.  *)
  117.  
  118. procedure skip_rest;
  119. begin
  120.    dos_lseek(infd,header.compressed_size-incnt,seek_cur);
  121.    fileeof := true;
  122.    header.compressed_size := 0;
  123.    incnt := 0;
  124. end;
  125.  
  126. procedure skip_csize;
  127. begin
  128.    incnt := 0;
  129.    skip_rest;
  130. end;
  131.  
  132. procedure ReadByte(var x: byte);
  133. begin
  134.    if incnt = 0 then
  135.    begin
  136.       if header.compressed_size = 0 then
  137.       begin
  138.          fileeof := true;
  139.          exit;
  140.       end;
  141.  
  142.       inpos := sizeof(inbuf);
  143.       if inpos > header.compressed_size then
  144.          inpos := header.compressed_size;
  145.       incnt := dos_read(infd,inbuf,inpos);
  146.  
  147.       inpos := 1;
  148.       dec(header.compressed_size,incnt);
  149.    end;
  150.  
  151.    x := inbuf[inpos];
  152.    inc(inpos);
  153.    dec(incnt);
  154. end;
  155.  
  156.  
  157. (* ------------------------------------------------------------- *)
  158. procedure OutByte (c: integer);
  159.    (* output each character from archive to screen *)
  160.  
  161.    procedure flushbuf;
  162.    begin
  163.       disp(uoutbuf);
  164.       uoutbuf := '';
  165.    end;
  166.  
  167.    procedure addchar;
  168.    begin
  169.       inc(uoutbuf[0]);
  170.       uoutbuf[length(uoutbuf)] := chr(c);
  171.    end;
  172.  
  173.    procedure not_text;
  174.    begin
  175.       newline;
  176.       displn('This is not a text file!');
  177.       skip_rest;
  178.    end;
  179.    
  180. begin
  181.    outbuf[outpos mod obufsize] := c;
  182.    inc(outpos);
  183.  
  184. (********
  185. if c = 13 then
  186. else if c = 10 then begin
  187. if nomore then skip_rest else newline;
  188. end else write(chr(c));
  189. exit;
  190. ********)
  191.  
  192.    case c of
  193.    13:  begin
  194.            if linenum < 1000 then
  195.            begin
  196.               flushbuf;
  197.               newline;
  198.            end;
  199.  
  200.            if nomore or dump_user then
  201.               skip_rest;
  202.         end;
  203.  
  204.    10: ;              
  205.  
  206.    26: begin
  207.           flushbuf;
  208.           skip_rest;         {jump to nomore mode on ^z}
  209.        end;
  210.  
  211.    8,9,32..255:
  212.        begin
  213.           if length(uoutbuf) >= max_linelen then
  214.           begin
  215.              flushbuf;
  216.              if header.compressed_size > 10 then
  217.                 not_text;
  218.           end;
  219.  
  220.           if linenum < 1000 then   {stop display on nomore}
  221.              addchar;
  222.        end;
  223.  
  224.    else
  225.       begin
  226.          if binary_count < max_binary then
  227.             inc(binary_count)
  228.          else
  229.          if header.compressed_size > 10 then
  230.             not_text;
  231.       end;
  232.    end;
  233.  
  234. end;
  235.  
  236.  
  237. (* ---------------------------------------------------------- *)
  238.  
  239. {$i unlzh.inc}    {lzh expander}
  240.  
  241.  
  242. (* ---------------------------------------------------------- *)
  243. (*
  244.  * This procedure displays the text contents of a specified archive
  245.  * file.  The filename must be fully specified and verified.
  246.  *
  247.  *)
  248.  
  249. procedure viewfile;
  250. var
  251.    b: byte;
  252.  
  253. begin
  254.    newline;
  255.    default_color;
  256.    binary_count := 0;
  257.    getbuf := 0;
  258.    getlen := 0;
  259.    incnt := 0;
  260.    outpos := 0;
  261.    uoutbuf := '';
  262.    fileeof := false;
  263.  
  264.    if header.compression_type = '-lh0-' then
  265.       while (not fileeof) and (not dump_user) do
  266.       begin
  267.          ReadByte(b);
  268.          OutByte(b);
  269.       end
  270.    else
  271.  
  272.    if header.compression_type = '-lh1-' then
  273.       UnLZHuf
  274.    else
  275.  
  276.       displn('Unknown compression method.');
  277.  
  278.    if nomore=false then
  279.       newline;
  280.    linenum := 1;
  281. end;
  282.  
  283.  
  284. (* ---------------------------------------------------------- *)
  285. procedure _itoa(i: integer; var sp);
  286. var
  287.    s: array[1..2] of char absolute sp;
  288. begin
  289.    s[1] := chr( (i div 10) + ord('0'));
  290.    s[2] := chr( (i mod 10) + ord('0'));
  291. end;
  292.  
  293. function format_date(date: word): string8;
  294. const
  295.    s:       string8 = 'mm-dd-yy';
  296. begin
  297.    _itoa(((date shr 9) and 127)+80, s[7]);
  298.    _itoa( (date shr 5) and 15,  s[1]);
  299.    _itoa( (date      ) and 31,  s[4]);
  300.    format_date := s;
  301. end;
  302.  
  303. function format_time(time: word): string8;
  304. const
  305.    s:       string8 = 'hh:mm:ss';
  306. begin
  307.    _itoa( (time shr 11) and 31, s[1]);
  308.    _itoa( (time shr  5) and 63, s[4]);
  309.    _itoa( (time shl  1) and 63, s[7]);
  310.    format_time := s;
  311. end;
  312.  
  313.  
  314. (* ---------------------------------------------------------- *)
  315. procedure process_file_header;
  316. var
  317.    n:             word;
  318.    fpos:          longint;
  319.    filename:      dos_filename;
  320.  
  321. begin
  322.    dos_lseek(infd,0,seek_cur);
  323.    fpos := dos_tell;
  324.  
  325.    while (dump_user = false) do
  326.    begin
  327.       set_function(fun_arcview);
  328.  
  329.       dos_lseek(infd,fpos,seek_start);
  330.       n := dos_read(infd,header.header_check,sizeof(byte));
  331.       n := dos_read(infd,header.compression_type,sizeof(header.compression_type));
  332.       n := dos_read(infd,header.compressed_size,sizeof(longint));
  333.       n := dos_read(infd,header.original_size,sizeof(longint));
  334.       n := dos_read(infd,header.file_time,sizeof(word));
  335.       n := dos_read(infd,header.file_date,sizeof(word));
  336.       n := dos_read(infd,header.file_attributes,sizeof(word));
  337.       n := dos_read(infd,header.file_name_length,sizeof(byte));
  338.       n := dos_read(infd,header.file_name[1],header.file_name_length);
  339.       n := dos_read(infd,header.crc16,sizeof(word));
  340.       header.file_name[0] := chr(header.file_name_length);
  341.       filename := remove_path(header.file_name);
  342.       stoupper(filename);
  343.  
  344.  
  345.       (* exclude the file if outside current pattern *)
  346.       if nomore or (not wildcard_match(pattern,filename)) then
  347.       begin
  348.          skip_csize;
  349.          exit;
  350.       end;
  351.  
  352.       (* display file information headers if needed *)
  353.       if not header_present then
  354.       begin
  355.          header_present := true;
  356.  
  357.          newline;
  358.          disp(' File Name    Length   Method     Date      Time');
  359.          if expand_files then disp('    (Enter) or (S)kip, (V)iew');
  360.          newline;
  361.  
  362.          disp('------------  ------  --------  --------  --------');
  363.          if expand_files then disp('  -------------------------');
  364.          newline;
  365.       end;
  366.  
  367.  
  368.       (* display file information *)
  369.       disp(ljust(filename,12)+' '+
  370.            rjust(ltoa(header.original_size),7)+'    '+
  371.            header.compression_type+'   '+
  372.            format_date(header.file_date)+'  '+
  373.            format_time(header.file_time));
  374.  
  375.       if not expand_files then
  376.       begin
  377.          skip_csize;
  378.          newline;
  379.          exit;
  380.       end;
  381.  
  382.  
  383.       (* determine action to perform on this member file *)
  384.       action := 'S';
  385.       disp('  Action? ');
  386.       input(action,1);
  387.       stoupper(action);
  388.  
  389.       case action[1] of
  390.          'S':
  391.             begin
  392.                displn(' [Skip]');
  393.                skip_csize;
  394.                exit;
  395.             end;
  396.  
  397.          'V','R':
  398.             begin
  399.                displn(' [View]');
  400.                viewfile;
  401.  
  402.                header_present := false;
  403.             {  make_log_entry('View archive member ('+extname
  404.                                         +') from ('+remove_path(arcname)
  405.                                         +')',true); }
  406.             end;
  407.  
  408.          'Q':
  409.             begin
  410.                displn(' [Quit]');
  411.                dos_lseek(infd,0,seek_end);
  412.                exit;
  413.             end;
  414.  
  415.          else
  416.             displn(' [Type S, V or Q!]');
  417.       end;
  418.    end;
  419. end;
  420.  
  421.  
  422. (* ---------------------------------------------------------- *)
  423. procedure process_headers;
  424. var
  425.    n: integer;
  426.  
  427. begin
  428.    dos_lseek(infd,0,seek_start);
  429.    header_present := false;
  430.  
  431.    while (not dump_user) do
  432.    begin
  433.       n := dos_read(infd,header.header_length,sizeof(byte));
  434.  
  435.       if (header.header_length = 0) or (n = 0) then
  436.          exit
  437.       else
  438.  
  439.       if header.header_length >= 22 then
  440.          process_file_header
  441.       else
  442.  
  443.       begin
  444.          displn('Invalid file Header');
  445.          exit;
  446.       end;
  447.    end;
  448.  
  449. end;
  450.  
  451.  
  452. (* ---------------------------------------------------------- *)
  453. procedure select_pattern;
  454. begin
  455.    default_pattern := '*.*';
  456.  
  457.    while true do
  458.    begin
  459.       newline;
  460.       disp(remove_path(infn));
  461.       get_def(': View member filespec:', enter_eq+default_pattern+'? ');
  462.       
  463.       get_nextpar;
  464.       pattern := par;
  465.       stoupper(pattern);
  466.       if length(pattern) = 0 then
  467.          pattern := default_pattern;
  468.  
  469.       if (pattern = 'none') or (pattern = 'Q') or dump_user then
  470.          exit;
  471.    
  472.       process_headers;
  473.    
  474.       default_pattern := 'none';
  475.    end;
  476. end;
  477.  
  478.  
  479. (* ---------------------------------------------------------- *)
  480. procedure view_file;
  481. begin
  482.    infd := dos_open(infn,open_read);
  483.    if infd = dos_error then
  484.       exit;
  485.  
  486.    if expand_files then
  487.       select_pattern
  488.    else
  489.    begin
  490.       pattern := '*.*';
  491.       process_headers;
  492.    end;
  493.  
  494.    dos_close(infd);
  495. end;
  496.  
  497.  
  498.  
  499. (* ---------------------------------------------------------- *)
  500. procedure process_file(name: filenames);
  501. var
  502.    mem:    longint;
  503.  
  504. begin
  505.    linenum := 1;
  506.    cmdline := '';
  507.    expand_files := false;
  508.    infn := name;
  509.    view_file;
  510.  
  511.    newline;
  512.    get_def('View text files in this .LZH file:','(Enter)=yes? ');
  513.  
  514.    (* process text viewing if desired *)
  515.    get_nextpar;
  516.    if par[1] <> 'N' then
  517.    begin
  518.       expand_files := true;
  519.       view_file;
  520.    end;
  521. end;
  522.  
  523.  
  524. (*
  525.  * main program
  526.  *
  527.  *)
  528.  
  529. var
  530.    i:      integer;
  531.    par:    anystring;
  532.  
  533. begin
  534.    gotoxy(60,24); reverseVideo; disp(' LzhTV ');
  535.  
  536.    SetScrollPoint(23);
  537.    gotoxy(1,23);  lowVideo;
  538.    linenum := 1;
  539.  
  540.    if paramcount = 0 then
  541.    begin
  542. {     newline;
  543.       displn(version);
  544.       displn('Courtesy of:  S.H.Smith  and  The Tool Shop BBS,  (602) 279-2673.');
  545.       newline;  }
  546.  
  547.       displn('Usage:  LzhTV [-Pport] [-Tminutes] FILE[.file]');
  548.  
  549. {     newline;
  550.       displn('-Pn   enables com port COMn and monitors carrier');
  551.       displn('-Tn   allows user to stay in program for n minutes');  }
  552.  
  553.       halt;
  554.    end;
  555.  
  556.    for i := 1 to paramcount do
  557.    begin
  558.       par := paramstr(i);
  559.  
  560.       if par[1] = '-' then
  561.          case upcase(par[2]) of
  562.             'P':  opencom(ord(par[3]) - ord('0'));
  563.             'T':  tlimit := atoi(copy(par,3,5));
  564.          end
  565.       else
  566.  
  567.       begin
  568.         if pos('.',par) = 0 then
  569.             par := par + '.LZH';
  570.  
  571.         if dos_exists(par) then
  572.             process_file(par)
  573.         else
  574.             displn('File not found: '+par);
  575.       end;
  576.    end;
  577.  
  578.    newline;
  579.    displn(version);
  580.    closecom;
  581. end.
  582.  
  583.